home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 1 code / the Palette Manager / Sample.f / Sample.p < prev    next >
Encoding:
Text File  |  1989-09-20  |  17.3 KB  |  654 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Sample Application
  6. #
  7. #    Sample
  8. #
  9. #    Sample.p    -    Pascal Source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #                1.00                08/88
  16. #                1.01                11/88
  17. #                1.02                04/89    MPW 3.1
  18. #
  19. #    Components:
  20. #                Sample.p            April 1, 1989
  21. #                Sample.c            April 1, 1989
  22. #                Sample.a            April 1, 1989
  23. #                Sample.inc1.a        April 1, 1989
  24. #                SampleMisc.a        April 1, 1989
  25. #                Sample.r            April 1, 1989
  26. #                Sample.h            April 1, 1989
  27. #                [P]Sample.make        April 1, 1989
  28. #                [C]Sample.make        April 1, 1989
  29. #                [A]Sample.make        April 1, 1989
  30. #
  31. #    Sample is an example application that demonstrates how to
  32. #    initialize the commonly used toolbox managers, operate 
  33. #    successfully under MultiFinder, handle desk accessories, 
  34. #    and create, grow, and zoom windows.
  35. #
  36. #    It does not by any means demonstrate all the techniques 
  37. #    you need for a large application. In particular, Sample 
  38. #    does not cover exception handling, multiple windows/documents, 
  39. #    sophisticated memory management, printing, or undo. All of 
  40. #    these are vital parts of a normal full-sized application.
  41. #
  42. #    This application is an example of the form of a Macintosh 
  43. #    application; it is NOT a template. It is NOT intended to be 
  44. #    used as a foundation for the next world-class, best-selling, 
  45. #    600K application. A stick figure drawing of the human body may 
  46. #    be a good example of the form for a painting, but that does not 
  47. #    mean it should be used as the basis for the next Mona Lisa.
  48. #
  49. #    We recommend that you review this program or TESample before 
  50. #    beginning a new application.
  51. #
  52. ------------------------------------------------------------------------------}
  53.  
  54.  
  55. PROGRAM Sample;
  56.  
  57.  
  58. {Segmentation strategy:
  59.  
  60.  This program consists of three segments. Main contains most of the code,
  61.  including the MPW libraries, and the main program. Initialize contains
  62.  code that is only used once, during startup, and can be unloaded after the
  63.  program starts. %A5Init is automatically created by the Linker to initialize
  64.  globals for the MPW libraries and is unloaded right away.}
  65.  
  66.  
  67. {SetPort strategy:
  68.  
  69.  Toolbox routines do not change the current port. In spite of this, we use 
  70.  a strategy of calling SetPort whenever we want to draw or make calls which depend
  71.  on the current port. This makes us less vulnerable to bugs in other software which
  72.  might alter the current port (such as the bug (feature?) in many desk accessories
  73.  which change the port on OpenDeskAcc).  Hopefully, this also makes the routines
  74.  from this program more self-contained, since they don't depend on the current
  75.  port setting.}
  76.  
  77.  
  78. USES
  79.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps;
  80.  
  81. CONST
  82.  
  83.     kSysEnvironsVersion        = 1;
  84.  
  85.     kOSEvent                = app4Evt;    {event used by MultiFinder}
  86.     kSuspendResumeMessage    = 1;        {high byte of suspend/resume event message}
  87.     kResumeMask                = 1;        {bit of message field for resume vs. suspend}
  88.     kNoEvents                = 0;        {no events mask}
  89.      
  90.     kMinHeap    = 21 * 1024;
  91.      
  92.     kMinSpace    = 8 * 1024;
  93.     
  94.     {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
  95.     kExtremeNeg    = -32768;
  96.     kExtremePos    = 32767 - 1;            {required for old region bug}
  97.     
  98.     {These constants are all resource IDs, corresponding to resources in Sample.r.}
  99.     rMenuBar    = 128;                    {application's menu bar}
  100.     rAboutAlert    = 128;                    {about alert}
  101.     rUserAlert    = 129;                    {error user alert}
  102.     rWindow        = 128;                    {application's window}
  103.     rStopRect    = 128;                    {rectangle for Stop light}
  104.     rGoRect        = 129;                    {rectangle for Go light}
  105.  
  106.     {These constants are used to identify menus and their items. The menu IDs
  107.      have an "m" prefix and the item numbers within each menu have an "i" prefix.}
  108.     mApple        = 128;                    {Apple menu}
  109.     iAbout        = 1;
  110.  
  111.     mFile        = 129;                    {File menu}
  112.     iNew        = 1;
  113.     iClose        = 4;
  114.     iQuit        = 12;
  115.  
  116.     mEdit        = 130;                    {Edit menu}
  117.     iUndo        = 1;
  118.     iCut        = 3;
  119.     iCopy        = 4;
  120.     iPaste        = 5;
  121.     iClear        = 6;
  122.  
  123.     mLight        = 131;                    {Light menu}
  124.     iStop        = 1;
  125.     iGo            = 2;
  126.     
  127.     {1.01 - kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  128.     kDITop        = $0050;
  129.     kDILeft        = $0070;
  130.  
  131.  
  132. VAR
  133.     {The "g" prefix is used to emphasize that a variable is global.}
  134.  
  135.     gMac                : SysEnvRec;    {set up by Initialize}
  136.     gHasWaitNextEvent    : BOOLEAN;        {set up by Initialize}
  137.     gInBackground        : BOOLEAN;        {maintained by Initialize and DoEvent}
  138.     gStopped            : BOOLEAN;        {maintained by Initialize and SetLight}
  139.     gStopRect            : Rect;            {set up by Initialize}
  140.     gGoRect                : Rect;            {set up by Initialize}
  141.  
  142.  
  143. {$S Initialize}
  144. FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
  145.  
  146. BEGIN
  147.     IF (tType = ToolTrap) &
  148.         (gMac.machineType > envMachUnknown) &
  149.         (gMac.machineType < envMacII) THEN BEGIN        {it's a 512KE, Plus, or SE}
  150.         tNumber := BAND(tNumber, $03FF);
  151.         IF tNumber > $01FF THEN                            {which means the tool traps}
  152.             tNumber := _Unimplemented;                    {only go to $01FF}
  153.     END;
  154.     TrapAvailable := NGetTrapAddress(tNumber, tType) <>
  155.                         GetTrapAddress(_Unimplemented);
  156. END; {TrapAvailable}
  157.  
  158.  
  159. {$S Main}
  160. FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
  161.  
  162. {Check if a window belongs to a desk accessory.}
  163.  
  164. BEGIN
  165.     IF window = NIL THEN
  166.         IsDAWindow := FALSE
  167.     ELSE    {DA windows have negative windowKinds}
  168.         IsDAWindow := WindowPeek(window)^.windowKind < 0;
  169. END; {IsDAWindow}
  170.  
  171.  
  172. {$S Main}
  173. FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
  174.  
  175. BEGIN
  176.     IF window = NIL THEN
  177.         IsAppWindow := FALSE
  178.     ELSE    {application windows have windowKinds = userKind (8)}
  179.         WITH WindowPeek(window)^ DO
  180.             IsAppWindow := (windowKind = userKind);
  181. END; {IsAppWindow}
  182.  
  183.  
  184. {$S Main}
  185. PROCEDURE AlertUser;
  186.  
  187. VAR
  188.     itemHit    : INTEGER;
  189. BEGIN
  190.     SetCursor(arrow);
  191.     itemHit := Alert(rUserAlert, NIL);
  192.     ExitToShell;
  193. END; {AlertUser}
  194.  
  195.  
  196. {$S Main}
  197. FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
  198.  
  199. {Close a window.}
  200.  
  201. BEGIN
  202.     DoCloseWindow := TRUE;
  203.     IF IsDAWindow(window) THEN
  204.         CloseDeskAcc(WindowPeek(window)^.windowKind);
  205.     IF IsAppWindow(window) THEN
  206.         CloseWindow(window);
  207. END; {DoCloseWindow}
  208.  
  209.  
  210. {$S Initialize}
  211. FUNCTION GoGetRect(rectID: INTEGER; VAR theRect: Rect) : BOOLEAN;
  212.  
  213. TYPE
  214.     RectPtr        = ^Rect;
  215.     RectHnd        = ^RectPtr;
  216. VAR
  217.     resource    : Handle;
  218. BEGIN
  219.     resource := GetResource('RECT', rectID);
  220.     IF resource <> NIL THEN BEGIN
  221.         GoGetRect := TRUE;
  222.         theRect := RectHnd(resource)^^;
  223.         END
  224.     ELSE
  225.         GoGetRect := FALSE;
  226. END; {GoGetRect}
  227.  
  228.  
  229. {$S Initialize}
  230. PROCEDURE Initialize;
  231.  
  232. VAR
  233.     menuBar            : Handle;
  234.     window            : WindowPtr;
  235.     ignoreError        : OSErr;
  236.     total, contig    : LongInt;
  237.     ignoreResult    : BOOLEAN;
  238.     event            : EventRecord;
  239.     count            : INTEGER;
  240.  
  241. BEGIN
  242.     gInBackground := FALSE;
  243.  
  244.     InitGraf(@thePort);
  245.     InitFonts;
  246.     InitWindows;
  247.     InitMenus;
  248.     TEInit;
  249.     InitDialogs(NIL);
  250.     InitCursor;
  251.      
  252.     FOR count := 1 TO 3 DO
  253.         ignoreResult := EventAvail(everyEvent, event);
  254.          
  255.     ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
  256.     
  257.     {Make sure that the machine has at least 128K ROMs. If it doesn't, exit.}
  258.     
  259.     IF gMac.machineType < 0 THEN AlertUser;
  260.          
  261.     gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  262.      
  263.     IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN AlertUser;
  264.          
  265.     PurgeSpace(total, contig);
  266.     IF total < kMinSpace THEN AlertUser;
  267.  
  268.     window := WindowPtr(NewPtr(SIZEOF(WindowRecord)));
  269.     IF window = NIL THEN AlertUser;
  270.     window := GetNewWindow(rWindow, Ptr(window), WindowPtr(-1));
  271.  
  272.     menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  273.     IF menuBar = NIL THEN AlertUser;
  274.     SetMenuBar(menuBar);                    {install menus}
  275.     DisposHandle(menuBar);
  276.     AddResMenu(GetMHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  277.     DrawMenuBar;
  278.  
  279.     gStopped := TRUE;
  280.     IF NOT GoGetRect(rStopRect, gStopRect) THEN
  281.         AlertUser;                            {the stop light rectangle}
  282.     IF NOT GoGetRect(rGoRect, gGoRect) THEN
  283.         AlertUser;                            {the go light rectangle}
  284. END; {Initialize}
  285.  
  286.  
  287. {$S Main}
  288. PROCEDURE Terminate;
  289.  
  290. {Clean up the application and exits. We close all of the windows so that
  291.  they can update their documents, if any.}
  292.  
  293. {1.01 - If we find out that a cancel has occurred, we won't exit to the
  294.  shell, but will return instead.}
  295.  
  296. VAR
  297.     aWindow    : WindowPtr;
  298.     closed    : BOOLEAN;
  299.  
  300. BEGIN
  301.     closed := TRUE;
  302.     REPEAT
  303.         aWindow := FrontWindow;                    {get the current front window}
  304.         IF aWindow <> NIL THEN
  305.             closed := DoCloseWindow(aWindow);    {close this window}
  306.     UNTIL (NOT closed) | (aWindow = NIL);        {do all windows}
  307.     IF closed THEN
  308.         ExitToShell;                            {exit if no cancellation}
  309. END; {Terminate}
  310.  
  311.  
  312. {$S Main}
  313. PROCEDURE SetLight(window: WindowPtr; newStopped: BOOLEAN);
  314.  
  315. {Change the setting of the light.}
  316.  
  317. BEGIN
  318.     IF newStopped <> gStopped THEN BEGIN
  319.         gStopped := newStopped;
  320.         SetPort(window);
  321.         InvalRect(window^.portRect);
  322.     END;
  323. END; {SetLight}
  324.  
  325.  
  326. {$S Main}
  327. PROCEDURE AdjustMenus;
  328.  
  329. VAR
  330.     window            : WindowPtr;
  331.     menu            : MenuHandle;
  332.  
  333. BEGIN
  334.     window := FrontWindow;
  335.  
  336.     menu := GetMHandle(mFile);
  337.     IF IsDAWindow(window) THEN                {we can allow desk accessories to be closed from the menu}
  338.         EnableItem(menu, iClose)
  339.     ELSE
  340.         DisableItem(menu, iClose);            {but not our traffic light window}
  341.  
  342.     menu := GetMHandle(mEdit);
  343.     IF IsDAWindow(window) THEN BEGIN        {a desk accessory might need the edit menu}
  344.         EnableItem(menu, iUndo);
  345.         EnableItem(menu, iCut);
  346.         EnableItem(menu, iCopy);
  347.         EnableItem(menu, iPaste);
  348.         EnableItem(menu, iClear);
  349.     END ELSE BEGIN                            {but we know we do not}
  350.         DisableItem(menu, iUndo);
  351.         DisableItem(menu, iCut);
  352.         DisableItem(menu, iCopy);
  353.         DisableItem(menu, iClear);
  354.         DisableItem(menu, iPaste);
  355.     END;
  356.  
  357.     menu := GetMHandle(mLight);
  358.     IF IsAppWindow(window) THEN BEGIN        {we know that it must be the traffic light}
  359.         EnableItem(menu, iStop);
  360.         EnableItem(menu, iGo);
  361.     END ELSE BEGIN
  362.         DisableItem(menu, iStop);
  363.         DisableItem(menu, iGo);
  364.     END;
  365.     CheckItem(menu, iStop, gStopped);        {we can also determine check/uncheck state, too}
  366.     CheckItem(menu, iGo, NOT gStopped);
  367. END; {AdjustMenus}
  368.  
  369.  
  370. {$S Main}
  371. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  372.  
  373. VAR
  374.     menuID            : INTEGER;        {the resource ID of the selected menu}
  375.     menuItem        : INTEGER;        {the item number of the selected menu}
  376.     itemHit            : INTEGER;
  377.     daName            : Str255;
  378.     daRefNum        : INTEGER;
  379.     handledByDA        : BOOLEAN;
  380.     ignore            : BOOLEAN;
  381.  
  382. BEGIN
  383.     menuID := HiWrd(menuResult);    {use built-ins (for efficiency)...}
  384.     menuItem := LoWrd(menuResult);    {to get menu item number and menu number}
  385.     CASE menuID OF
  386.         mApple:
  387.             CASE menuItem OF
  388.                 iAbout:                {bring up alert for About}
  389.                     itemHit := Alert(rAboutAlert, NIL);
  390.                 OTHERWISE BEGIN        {all non-About items in this menu are DAs}
  391.                     GetItem(GetMHandle(mApple), menuItem, daName);
  392.                     daRefNum := OpenDeskAcc(daName);
  393.                 END;
  394.             END;
  395.         mFile:
  396.             CASE menuItem OF
  397.                 iClose:
  398.                     ignore := DoCloseWindow(FrontWindow); {we don't care if cancelled}
  399.                 iQuit:
  400.                     Terminate;
  401.             END;
  402.         mEdit:                        {call SystemEdit for DA editing & MultiFinder}
  403.             handledByDA := SystemEdit(menuItem-1);    {since we don't do any editing}
  404.         mLight:
  405.             CASE menuItem OF
  406.                 iStop:
  407.                     SetLight(FrontWindow, TRUE);
  408.                 iGo:
  409.                     SetLight(FrontWindow, FALSE);
  410.             END;
  411.     END;
  412.     HiliteMenu(0);                    {unhighlight what MenuSelect (or MenuKey) hilited}
  413. END; {DoMenuCommand}
  414.  
  415.  
  416. {$S Main}
  417. PROCEDURE DrawWindow(window: WindowPtr);
  418.  
  419. BEGIN
  420.     SetPort(window);
  421.  
  422.     EraseRect(window^.portRect);    {clear out any garbage that might be left behind}
  423.     IF gStopped THEN                {draw a red (or white) stop light}
  424.         ForeColor(redColor)
  425.     ELSE
  426.         ForeColor(whiteColor);
  427.     PaintOval(gStopRect);
  428.     ForeColor(blackColor);
  429.     FrameOval(gStopRect);
  430.     IF NOT gStopped THEN            {draw a green (or white) go light}
  431.         ForeColor(greenColor)
  432.     ELSE
  433.         ForeColor(whiteColor);
  434.     PaintOval(gGoRect);
  435.     ForeColor(blackColor);
  436.     FrameOval(gGoRect);
  437. END; {DrawWindow}
  438.  
  439.  
  440. {$S Main}
  441. PROCEDURE DoContentClick(window: WindowPtr; event: EventRecord);
  442.  
  443. BEGIN
  444.     SetLight(window, NOT gStopped);
  445. END; {DoContentClick}
  446.  
  447.  
  448. {$S Main}
  449. PROCEDURE DoUpdate(window: WindowPtr);
  450.  
  451. BEGIN
  452.     IF IsAppWindow(window) THEN BEGIN
  453.         BeginUpdate(window);                    {sets up the visRgn, clears updateRgn}
  454.         IF NOT EmptyRgn(window^.visRgn) THEN    {draw if updating needs to be done}
  455.             DrawWindow(window);
  456.         EndUpdate(window);                        {restores the visRgn}
  457.     END;
  458. END; {DoUpdate}
  459.  
  460.  
  461. {$S Main}
  462. PROCEDURE DoActivate(window: WindowPtr; becomingActive: BOOLEAN);
  463.  
  464.  
  465. BEGIN
  466.     IF IsAppWindow(window) THEN
  467.         IF becomingActive THEN
  468.             {do whatever you need to at activation}
  469.         ELSE
  470.             {do whatever you need to at deactivation};
  471. END; {DoActivate}
  472.  
  473.  
  474. {$S Main}
  475. PROCEDURE GetGlobalMouse(VAR mouse: Point);
  476.  
  477.  
  478. VAR
  479.     event    : EventRecord;
  480.     
  481. BEGIN
  482.     IF OSEventAvail(kNoEvents, event) THEN;    {we aren't interested in any events}
  483.     mouse := event.where;                    {just the mouse position}
  484. END;
  485.  
  486.  
  487. {$S Main}
  488. PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
  489.  
  490. VAR
  491.     window                : WindowPtr;
  492.     arrowRgn            : RgnHandle;
  493.     plusRgn                : RgnHandle;
  494.     globalPortRect        : Rect;
  495.     
  496.  
  497. BEGIN
  498.     window := FrontWindow;    {we only adjust the cursor when we are in front}
  499.     IF (NOT gInBackground) AND (NOT IsDAWindow(window)) THEN BEGIN
  500.         {calculate regions for different cursor shapes}
  501.         arrowRgn := NewRgn;
  502.         plusRgn := NewRgn;
  503.  
  504.         {start with a big, big rectangular region}
  505.         {1.01 - changed to kExtremeNeg and kExtremePos for consistency}
  506.         SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg,
  507.                             kExtremePos, kExtremePos);
  508.  
  509.         {calculate plusRgn}
  510.         IF IsAppWindow(window) THEN BEGIN
  511.             SetPort(window);            {make a global version of the portRect}
  512.             SetOrigin(-window^.portBits.bounds.left, -window^.portBits.bounds.top);
  513.             globalPortRect := window^.portRect;
  514.             RectRgn(plusRgn, globalPortRect);
  515.             SectRgn(plusRgn, window^.visRgn, plusRgn);
  516.             SetOrigin(0, 0);
  517.         END;
  518.  
  519.         {subtract other regions from arrowRgn}
  520.         DiffRgn(arrowRgn, plusRgn, arrowRgn);
  521.  
  522.         {change the cursor and the region parameter}
  523.         IF PtInRgn(mouse, plusRgn) THEN BEGIN
  524.             SetCursor(GetCursor(plusCursor)^^);
  525.             CopyRgn(plusRgn, region);
  526.         END ELSE BEGIN
  527.             SetCursor(arrow);
  528.             CopyRgn(arrowRgn, region);
  529.         END;
  530.  
  531.         {get rid of our local regions}
  532.         DisposeRgn(arrowRgn);
  533.         DisposeRgn(plusRgn);
  534.     END;
  535. END; {AdjustCursor}
  536.  
  537.  
  538. {$S Main}
  539. PROCEDURE DoEvent(event: EventRecord);
  540.  
  541. {Do the right thing for an event. Determine what kind of event it is, and call
  542.  the appropriate routines.}
  543.  
  544. VAR
  545.     part, err    : INTEGER;
  546.     window        : WindowPtr;
  547.     hit            : BOOLEAN;
  548.     key            : CHAR;
  549.     aPoint        : Point;
  550.  
  551. BEGIN
  552.     CASE event.what OF
  553.         mouseDown: BEGIN
  554.             part := FindWindow(event.where, window);
  555.             CASE part OF
  556.                 inMenuBar: BEGIN            {process the menu command}
  557.                     AdjustMenus;
  558.                     DoMenuCommand(MenuSelect(event.where));
  559.                 END;
  560.                 inSysWindow:                {let the system handle the mouseDown}
  561.                     SystemClick(event, window);
  562.                 inContent:
  563.                     IF window <> FrontWindow THEN BEGIN
  564.                         SelectWindow(window);
  565.                         {DoEvent(event);}    {use this line for "do first click"}
  566.                     END ELSE
  567.                         DoContentClick(window, event);
  568.                 inDrag:                        {pass screenBits.bounds to get all gDevices}
  569.                     DragWindow(window, event.where, screenBits.bounds);
  570.                 inGrow:;
  571.                 inZoomIn, inZoomOut:;
  572.             END;
  573.         END;
  574.         keyDown, autoKey: BEGIN                {check for menukey equivalents}
  575.             key := CHR(BAnd(event.message, charCodeMask));
  576.             IF BAnd(event.modifiers, cmdKey) <> 0 THEN    {Command key down}
  577.                 IF event.what = keyDown THEN BEGIN
  578.                     AdjustMenus;            {enable/disable/check menu items properly}
  579.                     DoMenuCommand(MenuKey(key));
  580.                 END;
  581.         END;                                {call DoActivate with the window and...}
  582.         activateEvt:                        {TRUE for activate, FALSE for deactivate}
  583.             DoActivate(WindowPtr(event.message), BAnd(event.modifiers, activeFlag) <> 0);
  584.         updateEvt:                          {call DoUpdate with the window to update}
  585.             DoUpdate(WindowPtr(event.message));
  586.         {1.01 - It is not a bad idea to at least call DIBadMount in response
  587.          to a diskEvt, so that the user can format a floppy.}
  588.         diskEvt:
  589.             IF HiWrd(event.message) <> noErr THEN BEGIN
  590.                 SetPt(aPoint, kDILeft, kDITop);
  591.                 err := DIBadMount(aPoint, event.message);
  592.             END;
  593.         kOSEvent:
  594.             CASE BAnd(BRotL(event.message, 8), $FF) OF    {high byte of message}
  595.                 kSuspendResumeMessage: BEGIN
  596.                     gInBackground := BAnd(event.message, kResumeMask) = 0;
  597.                     DoActivate(FrontWindow, NOT gInBackground);
  598.                 END;
  599.             END;
  600.     END;
  601. END; {DoEvent}
  602.  
  603.  
  604. {$S Main}
  605. PROCEDURE EventLoop;
  606.  
  607. VAR
  608.     cursorRgn    : RgnHandle;
  609.     gotEvent    : BOOLEAN;
  610.     event        : EventRecord;
  611.     mouse        : Point;
  612.  
  613. BEGIN
  614.     cursorRgn := NewRgn;                {we’ll pass WNE an empty region the 1st time thru}
  615.     REPEAT
  616.         IF gHasWaitNextEvent THEN BEGIN    {put us 'asleep' forever under MultiFinder}
  617.             GetGlobalMouse(mouse);        {since we might go to sleep}
  618.             AdjustCursor(mouse, cursorRgn);
  619.             gotEvent := WaitNextEvent(everyEvent, event, MAXLONGINT, cursorRgn);
  620.         END ELSE BEGIN
  621.             SystemTask;                    {must be called if using GetNextEvent}
  622.             gotEvent := GetNextEvent(everyEvent, event);
  623.         END;
  624.         IF gotEvent THEN BEGIN
  625.             AdjustCursor(event.where, cursorRgn);    {make sure we have the right cursor}
  626.             DoEvent(event);
  627.         END;
  628.         {If you are using modeless dialogs that have editText items,
  629.          you will want to call IsDialogEvent to give the caret a chance
  630.          to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
  631.          for a non-NIL value before calling IsDialogEvent.}
  632.     UNTIL FALSE;                        {loop forever; we quit through an ExitToShell}
  633. END; {EventLoop}
  634.  
  635.  
  636. PROCEDURE _DataInit; EXTERNAL;
  637.  
  638. {$S Main}
  639. BEGIN
  640.     UnloadSeg(@_DataInit);    {note that _DataInit must not be in Main!}
  641.     
  642.     {1.01 - call to ForceEnvirons removed}
  643.     {If you have stack requirements that differ from the default,
  644.      then you could use SetApplLimit to increase StackSpace at 
  645.      this point, before calling MaxApplZone.}
  646.      
  647.     MaxApplZone;            {expand the heap so code segments load at the top}
  648.  
  649.     Initialize;                {initialize the program}
  650.     UnloadSeg(@Initialize);    {note that Initialize must not be in Main!}
  651.  
  652.     EventLoop;                {call the main event loop}
  653. END.
  654.